// @ts-nocheck
import React from 'react';
import { dynamic } from 'dumi';

export default {
  'batch-delete-confirm-demo': {
    component: function DumiDemo() {
  var _interopRequireDefault = require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/interopRequireDefault");

  var _regenerator = _interopRequireDefault(require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/regenerator"));

  var _asyncToGenerator2 = _interopRequireDefault(require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/esm/asyncToGenerator"));

  var _react = _interopRequireDefault(require("react"));

  var _antd = require("antd");

  var _raLib = require("ra-lib");

  var _default = function _default() {
    function handleDelete() {
      return _handleDelete.apply(this, arguments);
    }

    function _handleDelete() {
      _handleDelete = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
        return _regenerator.default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return (0, _raLib.batchDeleteConfirm)(8);

              case 2:
                alert('用户确定了！');

              case 3:
              case "end":
                return _context.stop();
            }
          }
        }, _callee);
      }));
      return _handleDelete.apply(this, arguments);
    }

    return /*#__PURE__*/_react.default.createElement(_antd.Button, {
      danger: true,
      onClick: handleDelete
    }, "\u5220\u9664");
  };

  return _react["default"].createElement(_default);
},
    previewerProps: {"sources":{"_":{"jsx":"import React from 'react';\nimport {Button} from 'antd';\n\nimport {batchDeleteConfirm} from 'ra-lib';\n\nexport default () => {\n    async function handleDelete(){\n        await batchDeleteConfirm(8);\n    \n        alert('用户确定了！')\n    }\n\n    return (<Button danger onClick={handleDelete}>删除</Button>)\n}"}},"dependencies":{"react":{"version":"^16.13.1"},"antd":{"version":"^4.9.2","css":"antd/dist/antd.css"},"ra-lib":{"version":"1.2.15"},"react-dom":{"version":"^16.13.1"},"@ant-design/icons":{"version":"^4.3.0"},"axios":{"version":"^0.21.1"},"classnames":{"version":"^2.2.6"},"flux-standard-action":{"version":"^2.1.1"},"jszip":{"version":"^3.5.0"},"lodash":{"version":"^4.17.19"},"lodash.camelcase":{"version":"^4.3.0"},"lodash.upperfirst":{"version":"^4.3.1"},"nprogress":{"version":"^0.2.0"},"path-to-regexp":{"version":"^6.1.0"},"prop-types":{"version":"^15.7.2"},"pubsub-js":{"version":"^1.8.0"},"qs":{"version":"^6.5.2"},"rc-util":{"version":"^5.5.0"},"react-copy-to-clipboard":{"version":"^5.0.2"},"react-helmet":{"version":"6.0.0-beta.2"},"react-redux":{"version":"^7.2.0"},"react-router-dom":{"version":"^5.1.2"},"react-sortable-hoc":{"version":"^1.11.0"},"redux":{"version":"^4.0.5"},"redux-actions":{"version":"^2.6.5"},"redux-thunk":{"version":"^2.3.0"},"uuid":{"version":"^7.0.3"}},"title":"基础用法","description":"<div class=\"markdown\"><p>配合 async await 使用</p></div>","identifier":"batch-delete-confirm-demo"},
  },
  'confirm-demo': {
    component: function DumiDemo() {
  var _interopRequireDefault = require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/interopRequireDefault");

  var _regenerator = _interopRequireDefault(require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/regenerator"));

  var _asyncToGenerator2 = _interopRequireDefault(require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/esm/asyncToGenerator"));

  var _react = _interopRequireDefault(require("react"));

  var _antd = require("antd");

  var _raLib = require("ra-lib");

  var _default = function _default() {
    function handleDelete() {
      return _handleDelete.apply(this, arguments);
    }

    function _handleDelete() {
      _handleDelete = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
        return _regenerator.default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return (0, _raLib.confirm)({
                  title: '温馨提示',
                  content: '您确定吗？'
                });

              case 2:
                alert('用户确定了！');

              case 3:
              case "end":
                return _context.stop();
            }
          }
        }, _callee);
      }));
      return _handleDelete.apply(this, arguments);
    }

    return /*#__PURE__*/_react.default.createElement(_antd.Button, {
      danger: true,
      onClick: handleDelete
    }, "\u5220\u9664");
  };

  return _react["default"].createElement(_default);
},
    previewerProps: {"sources":{"_":{"jsx":"import React from 'react';\nimport {Button} from 'antd';\n\nimport {confirm} from 'ra-lib';\n\nexport default () => {\n    async function handleDelete(){\n        await confirm({\n            title: '温馨提示',\n            content: '您确定吗？'\n        });\n    \n        alert('用户确定了！')\n    }\n\n    return (<Button danger onClick={handleDelete}>删除</Button>)\n}"}},"dependencies":{"react":{"version":"^16.13.1"},"antd":{"version":"^4.9.2","css":"antd/dist/antd.css"},"ra-lib":{"version":"1.2.15"},"react-dom":{"version":"^16.13.1"},"@ant-design/icons":{"version":"^4.3.0"},"axios":{"version":"^0.21.1"},"classnames":{"version":"^2.2.6"},"flux-standard-action":{"version":"^2.1.1"},"jszip":{"version":"^3.5.0"},"lodash":{"version":"^4.17.19"},"lodash.camelcase":{"version":"^4.3.0"},"lodash.upperfirst":{"version":"^4.3.1"},"nprogress":{"version":"^0.2.0"},"path-to-regexp":{"version":"^6.1.0"},"prop-types":{"version":"^15.7.2"},"pubsub-js":{"version":"^1.8.0"},"qs":{"version":"^6.5.2"},"rc-util":{"version":"^5.5.0"},"react-copy-to-clipboard":{"version":"^5.0.2"},"react-helmet":{"version":"6.0.0-beta.2"},"react-redux":{"version":"^7.2.0"},"react-router-dom":{"version":"^5.1.2"},"react-sortable-hoc":{"version":"^1.11.0"},"redux":{"version":"^4.0.5"},"redux-actions":{"version":"^2.6.5"},"redux-thunk":{"version":"^2.3.0"},"uuid":{"version":"^7.0.3"}},"title":"基础用法","description":"<div class=\"markdown\"><p>配合 async await 使用</p></div>","identifier":"confirm-demo"},
  },
  'context-menu-demo': {
    component: function DumiDemo() {
  var _interopRequireDefault = require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/interopRequireDefault");

  var _react = _interopRequireDefault(require("react"));

  var _antd = require("antd");

  var _raLib = require("ra-lib");

  var _default = function _default() {
    function handleMenuClick(key) {
      alert(key);
    }

    return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_raLib.ContextMenu, {
      content: /*#__PURE__*/_react.default.createElement(_antd.Menu, {
        selectable: false,
        onClick: function onClick(_ref) {
          var key = _ref.key;
          return handleMenuClick(key);
        }
      }, /*#__PURE__*/_react.default.createElement(_antd.Menu.Item, {
        key: "close"
      }, "\u5173\u95ED"), /*#__PURE__*/_react.default.createElement(_antd.Menu.Item, {
        key: "closeAll"
      }, "\u5173\u95ED\u5168\u90E8"))
    }, /*#__PURE__*/_react.default.createElement(_antd.Button, null, "\u53F3\u952E\u8BD5\u8BD5")));
  };

  return _react["default"].createElement(_default);
},
    previewerProps: {"sources":{"_":{"jsx":"import React from 'react';\nimport {Button, Menu} from 'antd';\n\nimport {ContextMenu} from 'ra-lib';\n\nexport default () => {\n    function handleMenuClick(key) {\n        alert(key);\n    }\n    return (\n        <div>\n            <ContextMenu\n                content={(\n                    <Menu\n                        selectable={false}\n                        onClick={({ key }) => handleMenuClick(key)}\n                    >\n                        <Menu.Item key=\"close\">\n                            关闭\n                        </Menu.Item>\n                        <Menu.Item key=\"closeAll\">\n                            关闭全部\n                        </Menu.Item>\n                    </Menu>\n                )}\n            >\n                <Button>右键试试</Button>\n            </ContextMenu>\n        </div>\n    );\n}"}},"dependencies":{"react":{"version":"^16.13.1"},"antd":{"version":"^4.9.2","css":"antd/dist/antd.css"},"ra-lib":{"version":"1.2.15"},"react-dom":{"version":"^16.13.1"},"@ant-design/icons":{"version":"^4.3.0"},"axios":{"version":"^0.21.1"},"classnames":{"version":"^2.2.6"},"flux-standard-action":{"version":"^2.1.1"},"jszip":{"version":"^3.5.0"},"lodash":{"version":"^4.17.19"},"lodash.camelcase":{"version":"^4.3.0"},"lodash.upperfirst":{"version":"^4.3.1"},"nprogress":{"version":"^0.2.0"},"path-to-regexp":{"version":"^6.1.0"},"prop-types":{"version":"^15.7.2"},"pubsub-js":{"version":"^1.8.0"},"qs":{"version":"^6.5.2"},"rc-util":{"version":"^5.5.0"},"react-copy-to-clipboard":{"version":"^5.0.2"},"react-helmet":{"version":"6.0.0-beta.2"},"react-redux":{"version":"^7.2.0"},"react-router-dom":{"version":"^5.1.2"},"react-sortable-hoc":{"version":"^1.11.0"},"redux":{"version":"^4.0.5"},"redux-actions":{"version":"^2.6.5"},"redux-thunk":{"version":"^2.3.0"},"uuid":{"version":"^7.0.3"}},"title":"基础用法","description":"<div class=\"markdown\"><p>右击弹出菜单</p></div>","identifier":"context-menu-demo"},
  },
  'copy-demo': {
    component: function DumiDemo() {
  var _interopRequireDefault = require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/interopRequireDefault");

  var _react = _interopRequireDefault(require("react"));

  var _raLib = require("ra-lib");

  var _default = function _default() {
    var content = '点击图标进行复制';
    return /*#__PURE__*/_react.default.createElement("div", null, content, ":", /*#__PURE__*/_react.default.createElement(_raLib.Copy, {
      text: content
    }));
  };

  return _react["default"].createElement(_default);
},
    previewerProps: {"sources":{"_":{"jsx":"import React from 'react';\nimport {Copy} from 'ra-lib';\n\nexport default () => {\n    const content = '点击图标进行复制';\n\n    return (\n        <div>\n            {content}:\n            <Copy text={content}/> \n        </div>\n    );\n}"}},"dependencies":{"react":{"version":"^16.13.1"},"ra-lib":{"version":"1.2.15"},"@ant-design/icons":{"version":"^4.3.0"},"antd":{"version":"^4.9.2","css":"antd/dist/antd.css"},"axios":{"version":"^0.21.1"},"classnames":{"version":"^2.2.6"},"flux-standard-action":{"version":"^2.1.1"},"jszip":{"version":"^3.5.0"},"lodash":{"version":"^4.17.19"},"lodash.camelcase":{"version":"^4.3.0"},"lodash.upperfirst":{"version":"^4.3.1"},"nprogress":{"version":"^0.2.0"},"path-to-regexp":{"version":"^6.1.0"},"prop-types":{"version":"^15.7.2"},"pubsub-js":{"version":"^1.8.0"},"qs":{"version":"^6.5.2"},"rc-util":{"version":"^5.5.0"},"react-copy-to-clipboard":{"version":"^5.0.2"},"react-dom":{"version":"^16.13.1"},"react-helmet":{"version":"6.0.0-beta.2"},"react-redux":{"version":"^7.2.0"},"react-router-dom":{"version":"^5.1.2"},"react-sortable-hoc":{"version":"^1.11.0"},"redux":{"version":"^4.0.5"},"redux-actions":{"version":"^2.6.5"},"redux-thunk":{"version":"^2.3.0"},"uuid":{"version":"^7.0.3"}},"title":"基础用法","description":"<div class=\"markdown\"><p>点击图标，复制内容</p></div>","identifier":"copy-demo"},
  },
  'icon-demo': {
    component: function DumiDemo() {
  var _interopRequireDefault = require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/interopRequireDefault");

  var _react = _interopRequireDefault(require("react"));

  var _index = _interopRequireDefault(require("D:/reactProjects/react-admin-library/src/components/icon/index"));

  var _default = function _default() {
    return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", null, "\u76F4\u63A5\u4F7F\u7528@ant-design/icons \u7EC4\u4EF6\u540D\u4F5C\u4E3Atype"), /*#__PURE__*/_react.default.createElement(_index.default, {
      type: "AppstoreOutlined",
      style: {
        color: 'red'
      }
    }), /*#__PURE__*/_react.default.createElement("div", null, "antd3.x type \u517C\u5BB9\u5904\u7406"), /*#__PURE__*/_react.default.createElement(_index.default, {
      type: "appstore"
    }));
  };

  return _react["default"].createElement(_default);
},
    previewerProps: {"sources":{"_":{"jsx":"import React from 'react';\nimport Icon from './index';\n\n\nexport default () => {\n    return (\n        <div>\n            <div>直接使用@ant-design/icons 组件名作为type</div>\n            <Icon type=\"AppstoreOutlined\" style={{ color: 'red' }}/>\n            \n            <div>antd3.x type 兼容处理</div>\n            <Icon type=\"appstore\"/>            \n        </div>\n    );\n};"},"index.jsx":{"import":"./index","content":"import React from 'react';\r\nimport PropTypes from 'prop-types';\r\nimport * as allIcons from '@ant-design/icons/es/icons';\r\nimport AntdIcon, { createFromIconfontCN, getTwoToneColor, setTwoToneColor } from '@ant-design/icons';\r\nimport { withThemeSuffix, removeTypeTheme, getThemeFromTypeName, alias } from './utils';\r\nimport warning from './warning';\r\n\r\nconst iconsMap = allIcons;\r\n\r\nfunction LegacyTypeIcon(props) {\r\n    const type = props.type;\r\n    const theme = props.theme;\r\n\r\n    // 直接使用 AppstoreOutlined 字符串作为type\r\n    let targetIconComponent = iconsMap[type];\r\n    if (targetIconComponent) {\r\n        return targetIconComponent ? React.createElement(targetIconComponent, props) : null;\r\n    }\r\n\r\n    if (theme) {\r\n        const themeInName = getThemeFromTypeName(type);\r\n        warning(!themeInName || theme === themeInName, 'Icon', 'The icon name \\''.concat(type, '\\' already specify a theme \\'').concat(themeInName, '\\',') + ' the \\'theme\\' prop \\''.concat(theme, '\\' will be ignored.'));\r\n    }\r\n\r\n    // antd 3 时兼容处理，type: appstore\r\n    const computedType = withThemeSuffix(removeTypeTheme(alias(type)), theme || 'outlined');\r\n    targetIconComponent = iconsMap[computedType];\r\n    warning(targetIconComponent, 'Icon', 'The icon name \\''.concat(type, '\\'').concat(theme ? 'with '.concat(theme) : '', ' doesn\\'t exist, please check it at https://ant.design/components/icon'));\r\n    return targetIconComponent ? React.createElement(targetIconComponent, props) : null;\r\n}\r\n\r\nfunction Icon(props) {\r\n    const { type, component, children } = props;\r\n\r\n    warning(Boolean(type || component || children), 'Icon', 'Should have `type` prop or `component` prop or `children`.');\r\n\r\n    if (component || children) {\r\n        return React.createElement(AntdIcon, Object.assign({}, props));\r\n    }\r\n\r\n    if (typeof type === 'string') {\r\n        return React.createElement(LegacyTypeIcon, Object.assign({}, props, {\r\n            type: type,\r\n        }));\r\n    }\r\n\r\n    return React.createElement(AntdIcon, null);\r\n}\r\n\r\nIcon.propTypes = {\r\n    /** @ant-design/icons AppstoreOutlined  antd3.x appstore */\r\n    type: PropTypes.string.isRequired,\r\n    style: PropTypes.object,\r\n    className: PropTypes.string,\r\n};\r\n\r\nIcon.createFromIconfontCN = createFromIconfontCN;\r\nIcon.getTwoToneColor = getTwoToneColor;\r\nIcon.setTwoToneColor = setTwoToneColor;\r\nexport default Icon;\r\n"},"utils.js":{"import":"./utils","content":"import camelCase from 'lodash.camelcase';\r\nimport upperFirst from 'lodash.upperfirst';\r\nimport warning from './warning'; // These props make sure that the SVG behaviours like general text.\r\n// Reference: https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4\r\n\r\nexport var svgBaseProps = {\r\n    width: '1em',\r\n    height: '1em',\r\n    fill: 'currentColor',\r\n    'aria-hidden': true,\r\n    focusable: 'false',\r\n}; // moved from https://github.com/ant-design/ant-design/blob/master/components/icon/utils.ts\r\n\r\nvar fillTester = /-fill$/;\r\nvar outlineTester = /-o$/;\r\nvar twoToneTester = /-twotone$/;\r\n\r\nexport function getThemeFromTypeName(type) {\r\n    var result = null;\r\n\r\n    if (fillTester.test(type)) {\r\n        result = 'filled';\r\n    } else if (outlineTester.test(type)) {\r\n        result = 'outlined';\r\n    } else if (twoToneTester.test(type)) {\r\n        result = 'twoTone';\r\n    }\r\n\r\n    return result;\r\n}\r\n\r\nexport function removeTypeTheme(type) {\r\n    return type.replace(fillTester, '').replace(outlineTester, '').replace(twoToneTester, '');\r\n}\r\n\r\nvar themeMap = {\r\n    filled: 'filled',\r\n    outlined: 'outlined',\r\n    twoTone: 'twoTone',\r\n};\r\n\r\nexport function withThemeSuffix(type, theme) {\r\n    var result = upperFirst(camelCase(type));\r\n    var realTheme = upperFirst(themeMap[theme]);\r\n\r\n    if (theme !== 'outlined' && !realTheme) {\r\n        warning(false, 'Icon', 'This icon \\''.concat(type, '\\' has unknown theme \\'').concat(theme, '\\''));\r\n    }\r\n\r\n    return result + realTheme;\r\n} // For alias or compatibility\r\n\r\nexport function alias(type) {\r\n    var newType = type;\r\n\r\n    switch (type) {\r\n        case 'cross':\r\n            newType = 'close';\r\n            break;\r\n        // https://github.com/ant-design/ant-design/issues/13007\r\n\r\n        case 'interation':\r\n            newType = 'interaction';\r\n            break;\r\n        // https://github.com/ant-design/ant-design/issues/16810\r\n\r\n        case 'canlendar':\r\n            newType = 'calendar';\r\n            break;\r\n        // https://github.com/ant-design/ant-design/issues/17448\r\n\r\n        case 'colum-height':\r\n            newType = 'column-height';\r\n            break;\r\n\r\n        default:\r\n    }\r\n\r\n    warning(newType === type, 'Icon', 'Icon \\''.concat(type, '\\' was a typo and is now deprecated, please use \\'').concat(newType, '\\' instead.'));\r\n    return newType;\r\n}\r\n"},"warning.js":{"import":"./warning","content":"import warning from 'rc-util/es/warning';\r\n\r\nexport default (function(valid, component, message) {\r\n    warning(valid, '[antd-compatible: '.concat(component, '] ').concat(message));\r\n});\r\n"}},"dependencies":{"react":{"version":">=16.9.0"},"prop-types":{"version":"15.7.2"},"@ant-design/icons":{"version":"4.5.0"},"lodash.camelcase":{"version":"4.3.0"},"lodash.upperfirst":{"version":"4.3.1"},"rc-util":{"version":"5.8.1"},"react-dom":{"version":">=16.9.0"}},"identifier":"icon-demo"},
  },
  'icon-demo-1': {
    component: function DumiDemo() {
  var _interopRequireDefault = require("D:/reactProjects/react-admin-library/node_modules/@babel/runtime/helpers/interopRequireDefault");

  var _react = _interopRequireDefault(require("react"));

  var _iconPicker = _interopRequireDefault(require("D:/reactProjects/react-admin-library/src/components/icon-picker"));

  var _default = function _default() {
    return /*#__PURE__*/_react.default.createElement(_iconPicker.default, null);
  };

  return _react["default"].createElement(_default);
},
    previewerProps: {"sources":{"_":{"jsx":"import React from 'react';\nimport IconPicker from '../icon-picker'\n\nexport default () => {\n\n    return (\n        <IconPicker/>\n    );\n}"},"icon-picker/index.jsx":{"import":"../icon-picker","content":"import React, { Component, Fragment } from 'react';\r\nimport { CloseCircleOutlined } from '@ant-design/icons';\r\nimport Icon from '../icon';\r\nimport IconModal from './IconModal';\r\n\r\nexport default class IconPicker extends Component {\r\n    state = {\r\n        visible: false,\r\n        type: 'user',\r\n    };\r\n\r\n    static getDerivedStateFromProps(nextProps, prevState) {\r\n        const { value } = nextProps;\r\n        return { type: value };\r\n    }\r\n\r\n    handleOk = (type) => {\r\n        const { onChange } = this.props;\r\n        if (onChange) onChange(type);\r\n\r\n        this.setState({ visible: false });\r\n    };\r\n\r\n    handleClear = (e) => {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        const { onChange } = this.props;\r\n        if (onChange) onChange();\r\n    };\r\n\r\n    render() {\r\n        const {\r\n            type,\r\n            visible,\r\n        } = this.state;\r\n        const { style } = this.props;\r\n\r\n        return (\r\n            <Fragment>\r\n                <div\r\n                    style={{\r\n                        ...style,\r\n                        display: 'flex',\r\n                        alignItems: 'center',\r\n                        justifyContent: 'space-between',\r\n                        height: 28,\r\n                        padding: '0 10px',\r\n                        border: '1px solid #d9d9d9',\r\n                        borderRadius: 4,\r\n                        cursor: 'pointer',\r\n                    }}\r\n                    onClick={() => this.setState({ visible: true })}\r\n                >\r\n                    {type ? (\r\n                        <Fragment>\r\n                            <Icon type={type}/>\r\n                            <CloseCircleOutlined onClick={this.handleClear}/>\r\n                        </Fragment>\r\n                    ) : (\r\n                        <span style={{ color: '#c7c7c7' }}>请选择图标</span>\r\n                    )}\r\n                </div>\r\n                <IconModal\r\n                    visible={visible}\r\n                    onOk={this.handleOk}\r\n                    onCancel={() => this.setState({ visible: false })}\r\n                />\r\n            </Fragment>\r\n        );\r\n    }\r\n}\r\n"},"icon/index.jsx":{"import":"./index","content":"import React from 'react';\r\nimport PropTypes from 'prop-types';\r\nimport * as allIcons from '@ant-design/icons/es/icons';\r\nimport AntdIcon, { createFromIconfontCN, getTwoToneColor, setTwoToneColor } from '@ant-design/icons';\r\nimport { withThemeSuffix, removeTypeTheme, getThemeFromTypeName, alias } from './utils';\r\nimport warning from './warning';\r\n\r\nconst iconsMap = allIcons;\r\n\r\nfunction LegacyTypeIcon(props) {\r\n    const type = props.type;\r\n    const theme = props.theme;\r\n\r\n    // 直接使用 AppstoreOutlined 字符串作为type\r\n    let targetIconComponent = iconsMap[type];\r\n    if (targetIconComponent) {\r\n        return targetIconComponent ? React.createElement(targetIconComponent, props) : null;\r\n    }\r\n\r\n    if (theme) {\r\n        const themeInName = getThemeFromTypeName(type);\r\n        warning(!themeInName || theme === themeInName, 'Icon', 'The icon name \\''.concat(type, '\\' already specify a theme \\'').concat(themeInName, '\\',') + ' the \\'theme\\' prop \\''.concat(theme, '\\' will be ignored.'));\r\n    }\r\n\r\n    // antd 3 时兼容处理，type: appstore\r\n    const computedType = withThemeSuffix(removeTypeTheme(alias(type)), theme || 'outlined');\r\n    targetIconComponent = iconsMap[computedType];\r\n    warning(targetIconComponent, 'Icon', 'The icon name \\''.concat(type, '\\'').concat(theme ? 'with '.concat(theme) : '', ' doesn\\'t exist, please check it at https://ant.design/components/icon'));\r\n    return targetIconComponent ? React.createElement(targetIconComponent, props) : null;\r\n}\r\n\r\nfunction Icon(props) {\r\n    const { type, component, children } = props;\r\n\r\n    warning(Boolean(type || component || children), 'Icon', 'Should have `type` prop or `component` prop or `children`.');\r\n\r\n    if (component || children) {\r\n        return React.createElement(AntdIcon, Object.assign({}, props));\r\n    }\r\n\r\n    if (typeof type === 'string') {\r\n        return React.createElement(LegacyTypeIcon, Object.assign({}, props, {\r\n            type: type,\r\n        }));\r\n    }\r\n\r\n    return React.createElement(AntdIcon, null);\r\n}\r\n\r\nIcon.propTypes = {\r\n    /** @ant-design/icons AppstoreOutlined  antd3.x appstore */\r\n    type: PropTypes.string.isRequired,\r\n    style: PropTypes.object,\r\n    className: PropTypes.string,\r\n};\r\n\r\nIcon.createFromIconfontCN = createFromIconfontCN;\r\nIcon.getTwoToneColor = getTwoToneColor;\r\nIcon.setTwoToneColor = setTwoToneColor;\r\nexport default Icon;\r\n"},"utils.js":{"import":"./utils","content":"import camelCase from 'lodash.camelcase';\r\nimport upperFirst from 'lodash.upperfirst';\r\nimport warning from './warning'; // These props make sure that the SVG behaviours like general text.\r\n// Reference: https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4\r\n\r\nexport var svgBaseProps = {\r\n    width: '1em',\r\n    height: '1em',\r\n    fill: 'currentColor',\r\n    'aria-hidden': true,\r\n    focusable: 'false',\r\n}; // moved from https://github.com/ant-design/ant-design/blob/master/components/icon/utils.ts\r\n\r\nvar fillTester = /-fill$/;\r\nvar outlineTester = /-o$/;\r\nvar twoToneTester = /-twotone$/;\r\n\r\nexport function getThemeFromTypeName(type) {\r\n    var result = null;\r\n\r\n    if (fillTester.test(type)) {\r\n        result = 'filled';\r\n    } else if (outlineTester.test(type)) {\r\n        result = 'outlined';\r\n    } else if (twoToneTester.test(type)) {\r\n        result = 'twoTone';\r\n    }\r\n\r\n    return result;\r\n}\r\n\r\nexport function removeTypeTheme(type) {\r\n    return type.replace(fillTester, '').replace(outlineTester, '').replace(twoToneTester, '');\r\n}\r\n\r\nvar themeMap = {\r\n    filled: 'filled',\r\n    outlined: 'outlined',\r\n    twoTone: 'twoTone',\r\n};\r\n\r\nexport function withThemeSuffix(type, theme) {\r\n    var result = upperFirst(camelCase(type));\r\n    var realTheme = upperFirst(themeMap[theme]);\r\n\r\n    if (theme !== 'outlined' && !realTheme) {\r\n        warning(false, 'Icon', 'This icon \\''.concat(type, '\\' has unknown theme \\'').concat(theme, '\\''));\r\n    }\r\n\r\n    return result + realTheme;\r\n} // For alias or compatibility\r\n\r\nexport function alias(type) {\r\n    var newType = type;\r\n\r\n    switch (type) {\r\n        case 'cross':\r\n            newType = 'close';\r\n            break;\r\n        // https://github.com/ant-design/ant-design/issues/13007\r\n\r\n        case 'interation':\r\n            newType = 'interaction';\r\n            break;\r\n        // https://github.com/ant-design/ant-design/issues/16810\r\n\r\n        case 'canlendar':\r\n            newType = 'calendar';\r\n            break;\r\n        // https://github.com/ant-design/ant-design/issues/17448\r\n\r\n        case 'colum-height':\r\n            newType = 'column-height';\r\n            break;\r\n\r\n        default:\r\n    }\r\n\r\n    warning(newType === type, 'Icon', 'Icon \\''.concat(type, '\\' was a typo and is now deprecated, please use \\'').concat(newType, '\\' instead.'));\r\n    return newType;\r\n}\r\n"},"warning.js":{"import":"./warning","content":"import warning from 'rc-util/es/warning';\r\n\r\nexport default (function(valid, component, message) {\r\n    warning(valid, '[antd-compatible: '.concat(component, '] ').concat(message));\r\n});\r\n"},"IconModal.jsx":{"import":"./IconModal","content":"import React, { Component } from 'react';\r\nimport PropTypes from 'prop-types';\r\nimport Icon from '../icon';\r\nimport { Row, Col, Button, Input } from 'antd';\r\nimport modal from '../../hoc/modal-hoc';\r\nimport ModalContent from '../../hoc/modal-hoc/ModalContent';\r\n\r\n\r\nconst icons = [\r\n    {\r\n        title: '方向性图标',\r\n        types: [ 'step-backward', 'step-forward', 'fast-backward', 'fast-forward', 'shrink', 'arrows-alt', 'down', 'up', 'left', 'right', 'caret-up', 'caret-down', 'caret-left', 'caret-right', 'up-circle', 'down-circle', 'left-circle', 'right-circle', 'double-right', 'double-left', 'vertical-left', 'vertical-right', 'forward', 'backward', 'rollback', 'enter', 'retweet', 'swap', 'swap-left', 'swap-right', 'arrow-up', 'arrow-down', 'arrow-left', 'arrow-right', 'play-circle', 'up-square', 'down-square', 'left-square', 'right-square', 'login', 'logout', 'menu-fold', 'menu-unfold', 'border-bottom', 'border-horizontal', 'border-inner', 'border-left', 'border-right', 'border-top', 'border-verticle', 'pic-center', 'pic-left', 'pic-right', 'radius-bottomleft', 'radius-bottomright', 'radius-upleft', 'fullscreen', 'fullscreen-exit' ],\r\n    },\r\n    {\r\n        title: '提示建议性图标',\r\n        types: [ 'question', 'question-circle', 'plus', 'plus-circle', 'pause', 'pause-circle', 'minus', 'minus-circle', 'plus-square', 'minus-square', 'info', 'info-circle', 'exclamation', 'exclamation-circle', 'close', 'close-circle', 'close-square', 'check', 'check-circle', 'check-square', 'clock-circle', 'warning', 'issues-close', 'stop' ],\r\n    },\r\n    {\r\n        title: '编辑类图标',\r\n        types: [ 'edit', 'form', 'copy', 'scissor', 'delete', 'snippets', 'diff', 'highlight', 'align-center', 'align-left', 'align-right', 'bg-colors', 'bold', 'italic', 'underline', 'strikethrough', 'redo', 'undo', 'zoom-in', 'zoom-out', 'font-colors', 'font-size', 'line-height', 'column-height', 'dash', 'small-dash', 'sort-ascending', 'sort-descending', 'drag', 'ordered-list', 'radius-setting' ],\r\n    },\r\n    {\r\n        title: '数据类图标',\r\n        types: [ 'area-chart', 'pie-chart', 'bar-chart', 'dot-chart', 'line-chart', 'radar-chart', 'heat-map', 'fall', 'rise', 'stock', 'box-plot', 'fund', 'sliders' ],\r\n    },\r\n    {\r\n        title: '网站通用图标',\r\n        types: [ 'lock', 'unlock', 'bars', 'book', 'calendar', 'cloud', 'cloud-download', 'code', 'copy', 'credit-card', 'delete', 'desktop', 'download', 'ellipsis', 'file', 'file-text', 'file-unknown', 'file-pdf', 'file-word', 'file-excel', 'file-jpg', 'file-ppt', 'file-markdown', 'file-add', 'folder', 'folder-open', 'folder-add', 'hdd', 'frown', 'meh', 'smile', 'inbox', 'laptop', 'appstore', 'link', 'mail', 'mobile', 'notification', 'paper-clip', 'picture', 'poweroff', 'reload', 'search', 'setting', 'share-alt', 'shopping-cart', 'tablet', 'tag', 'tags', 'to-top', 'upload', 'user', 'video-camera', 'home', 'loading', 'loading-3-quarters', 'cloud-upload', 'star', 'heart', 'environment', 'eye', 'eye-invisible', 'camera', 'save', 'team', 'solution', 'phone', 'filter', 'exception', 'export', 'customer-service', 'qrcode', 'scan', 'like', 'dislike', 'message', 'pay-circle', 'calculator', 'pushpin', 'bulb', 'select', 'switcher', 'rocket', 'bell', 'disconnect', 'database', 'compass', 'barcode', 'hourglass', 'key', 'flag', 'layout', 'printer', 'sound', 'usb', 'skin', 'tool', 'sync', 'wifi', 'car', 'schedule', 'user-add', 'user-delete', 'usergroup-add', 'usergroup-delete', 'man', 'woman', 'shop', 'gift', 'idcard', 'medicine-box', 'red-envelope', 'coffee', 'copyright', 'trademark', 'safety', 'wallet', 'bank', 'trophy', 'contacts', 'global', 'shake', 'api', 'fork', 'dashboard', 'table', 'profile', 'alert', 'audit', 'branches', 'build', 'border', 'crown', 'experiment', 'fire', 'money-collect', 'property-safety', 'read', 'reconciliation', 'rest', 'security-scan', 'insurance', 'interaction', 'safety-certificate', 'project', 'thunderbolt', 'block', 'cluster', 'deployment-unit', 'dollar', 'euro', 'pound', 'file-done', 'file-exclamation', 'file-protect', 'file-search', 'file-sync', 'gateway', 'gold', 'robot', 'shopping' ],\r\n    },\r\n    {\r\n        title: '品牌和标识',\r\n        types: [ 'android', 'apple', 'windows', 'ie', 'chrome', 'github', 'aliwangwang', 'dingding', 'weibo-square', 'weibo-circle', 'taobao-circle', 'html5', 'weibo', 'twitter', 'wechat', 'youtube', 'alipay-circle', 'taobao', 'skype', 'qq', 'medium-workmark', 'gitlab', 'medium', 'linkedin', 'google-plus', 'dropbox', 'facebook', 'codepen', 'code-sandbox', 'amazon', 'google', 'codepen-circle', 'alipay', 'ant-design', 'aliyun', 'zhihu', 'slack', 'slack-square', 'behance', 'behance-square', 'dribbble', 'dribbble-square', 'instagram', 'yuque', 'alibaba', 'yahoo' ],\r\n    },\r\n];\r\n\r\nclass IconPicker extends Component {\r\n    static propTypes = {\r\n        visible: PropTypes.bool,\r\n        title: PropTypes.any,\r\n        onOk: PropTypes.func,\r\n        onCancel: PropTypes.func,\r\n    };\r\n\r\n    state = {\r\n        selectedIcon: '',\r\n        dataSource: icons,\r\n    };\r\n\r\n    handleOk = () => {\r\n        const { onOk } = this.props;\r\n        const { selectedIcon } = this.state;\r\n\r\n        if (onOk) onOk(selectedIcon);\r\n    };\r\n\r\n    handleCancel = () => {\r\n        const { onCancel } = this.props;\r\n        if (onCancel) onCancel();\r\n    };\r\n\r\n    handleClick = (selectedIcon) => {\r\n        this.setState({ selectedIcon });\r\n    };\r\n\r\n    handleInputChange = (e) => {\r\n        const { value } = e.target;\r\n        const dataSource = icons.map(item => {\r\n            const types = item.types.filter(it => it.indexOf(value) !== -1);\r\n            return { ...item, types };\r\n        });\r\n\r\n        this.setState({ dataSource });\r\n    };\r\n\r\n    render() {\r\n        const { dataSource, selectedIcon } = this.state;\r\n        const windowHeight = document.documentElement.clientHeight;\r\n        return (\r\n            <ModalContent\r\n                onOk={this.handleOk}\r\n                onCancel={this.handleCancel}\r\n            >\r\n                <div style={{ padding: 10 }}>\r\n                    <div style={{ marginBottom: 16 }}>\r\n                        <Input.Search placeholder=\"Search\" onChange={this.handleInputChange}/>\r\n                    </div>\r\n                    <div style={{ height: windowHeight - 400, overflowY: 'scroll' }}>\r\n                        {dataSource.map(item => {\r\n                            const { title, types } = item;\r\n\r\n                            if (!types?.length) return null;\r\n\r\n                            return (\r\n                                <div key={title}>\r\n                                    <h3>{title}</h3>\r\n                                    <Row>\r\n                                        {types.map(type => {\r\n                                            return (\r\n                                                <Col style={{ marginBottom: 16 }} key={type} span={3}>\r\n                                                    <Button\r\n                                                        style={{\r\n                                                            display: 'flex',\r\n                                                            flexDirection: 'column',\r\n                                                            justifyContent: 'center',\r\n                                                            alignItems: 'center',\r\n                                                            width: 50,\r\n                                                            height: 50,\r\n                                                            cursor: 'pointer',\r\n                                                        }}\r\n                                                        type={selectedIcon === type ? 'primary' : 'default'}\r\n                                                        onClick={() => this.handleClick(type)}\r\n                                                    >\r\n                                                        <Icon style={{ fontSize: 20 }} type={type}/>\r\n                                                    </Button>\r\n                                                </Col>\r\n                                            );\r\n                                        })}\r\n                                    </Row>\r\n                                </div>\r\n                            );\r\n                        })}\r\n                    </div>\r\n                </div>\r\n            </ModalContent>\r\n        );\r\n    }\r\n}\r\n\r\nexport default modal('图标')(IconPicker);\r\n"},"hoc/modal-hoc/index.jsx":{"import":"../../hoc/modal-hoc","content":"import React, {Component} from 'react';\r\nimport {Modal} from 'antd';\r\n\r\n/**\r\n *  modal高级组件，确保每次弹框内部组件都是新创建的\r\n *  注：modal装饰器要放到所有其他装饰器上面（最外层）\r\n *\r\n * @param options 各种类型说明如下：\r\n *      string：modal 的 title\r\n *      function：返回值为 modal 的options\r\n *      object：Modal组件相关配置，具体配置参考antd Modal组件\r\n *          title: string | ReactNode | function(props)\r\n *          fullScreen: boolean 是否全屏显示modal\r\n *          其他 ant Modal 属性\r\n *\r\n * @param options\r\n * @returns {function(*): {displayName, new(): ModalComponent, prototype: ModalComponent}}\r\n */\r\nexport default (options) => WrappedComponent => {\r\n    const componentName = WrappedComponent.displayName || WrappedComponent.name || 'Component';\r\n\r\n    return class ModalComponent extends Component {\r\n        static displayName = `WithModal(${componentName})`;\r\n\r\n        render() {\r\n            const {visible, onCancel, top = 100, style} = this.props;\r\n            let title;\r\n\r\n            let others = {};\r\n\r\n            // options 如果是函数，返回值作为参数\r\n            if (typeof options === 'function') options = options(this.props);\r\n\r\n            // options 如果为字符串，直接作为title\r\n            if (typeof options === 'string') options = {title: options};\r\n\r\n            // options 如果为对象，获取title\r\n            if (typeof options === 'object') {\r\n                title = options.title;\r\n                others = options;\r\n            }\r\n\r\n            // 如果title为函数，返回值作为title\r\n            if (typeof title === 'function') title = title(this.props);\r\n\r\n            const {fullScreen} = others;\r\n\r\n            let fstl = {top};\r\n            if (fullScreen) {\r\n                fstl = {\r\n                    width: '100%',\r\n                    height: '100%',\r\n                    top: 0,\r\n                    paddingBottom: 0,\r\n                };\r\n            }\r\n\r\n            const stl = {\r\n                ...style,\r\n                ...fstl,\r\n            };\r\n\r\n            return (\r\n                <Modal\r\n                    destroyOnClose\r\n                    width=\"800px\"\r\n                    bodyStyle={{padding: 0}}\r\n                    style={stl}\r\n                    footer={null}\r\n                    maskClosable={false}\r\n\r\n                    {...others}\r\n                    title={title}\r\n                    onCancel={onCancel}\r\n                    visible={visible}\r\n                >\r\n                    <WrappedComponent {...this.props}/>\r\n                </Modal>\r\n            );\r\n        }\r\n    };\r\n};\r\n"},"hoc/modal-hoc/ModalContent.jsx":{"import":"../../hoc/modal-hoc/ModalContent","content":"import React, { Component } from 'react';\r\nimport { Button, Spin, ConfigProvider } from 'antd';\r\nimport PropTypes from 'prop-types';\r\nimport * as util from '../../util';\r\n\r\n/**\r\n * Modal 的内容容器，默认会使用屏幕剩余空间，内部内容滚动\r\n */\r\nexport default class ModalContent extends Component {\r\n    static contextType = ConfigProvider.ConfigContext;\r\n\r\n    state = {\r\n        height: 'auto',\r\n    };\r\n\r\n    static propTypes = {\r\n        surplusSpace: PropTypes.bool,   // 是否使用屏幕剩余空间\r\n        otherHeight: PropTypes.number,  // 除了主体内容之外的其他高度，用于计算主体高度；\r\n        loading: PropTypes.bool,        // 是否加载中\r\n        loadingTip: PropTypes.any,      // 加载中提示文案\r\n        footer: PropTypes.any,          // 底部\r\n        okHtmlType: PropTypes.any,      // 确定按钮类型\r\n        okText: PropTypes.any,          // 确定按钮文案\r\n        onOk: PropTypes.func,           // 确定事件\r\n        cancelText: PropTypes.any,      // 取消按钮文案\r\n        onCancel: PropTypes.func,       // 取消事件\r\n        resetText: PropTypes.any,       // 重置按钮文案\r\n        onReset: PropTypes.func,        // 表单重置事件\r\n\r\n        style: PropTypes.object,        // 最外层容器样式\r\n        bodyStyle: PropTypes.object,    // 内容容器样式\r\n    };\r\n\r\n    static defaultProps = {\r\n        loading: false,\r\n        style: {},\r\n        bodyStyle: {},\r\n        surplusSpace: false,\r\n        okText: '确定',\r\n        okHtmlType: '',\r\n        resetText: '重置',\r\n        cancelText: '取消',\r\n        onOk: () => void 0,\r\n        onCancel: () => void 0,\r\n    };\r\n\r\n    componentDidMount() {\r\n        const { surplusSpace } = this.props;\r\n\r\n        if (surplusSpace) {\r\n            this.handleWindowResize();\r\n            window.addEventListener('resize', this.handleWindowResize);\r\n        }\r\n    }\r\n\r\n    componentWillUnmount() {\r\n        const { surplusSpace } = this.props;\r\n\r\n        if (surplusSpace) window.removeEventListener('resize', this.handleWindowResize);\r\n    }\r\n\r\n    handleWindowResize = () => {\r\n        const prefixCls = this.context.getPrefixCls();\r\n\r\n        let { otherHeight } = this.props;\r\n        const windowHeight = document.documentElement.clientHeight;\r\n        if (!otherHeight) {\r\n            const top = util.getElementTop(this.wrapper);\r\n            let bottom = 24;\r\n            const antModalDom = util.getParentByClassName(this.wrapper, `${prefixCls}-modal`);\r\n\r\n            if (antModalDom) {\r\n                const classList = Array.from(antModalDom.classList);\r\n                const isFullScreen = classList.find(item => item.startsWith('full-screen'));\r\n\r\n                if (isFullScreen) bottom = 0;\r\n            }\r\n\r\n            otherHeight = top + bottom;\r\n        }\r\n        const height = windowHeight - otherHeight;\r\n\r\n        this.setState({ height });\r\n    };\r\n\r\n    render() {\r\n        const {\r\n            surplusSpace,\r\n            loading,\r\n            loadingTip,\r\n            otherHeight,\r\n            style,\r\n            bodyStyle,\r\n            footer,\r\n            okHtmlType,\r\n            okText,\r\n            resetText,\r\n            cancelText,\r\n            onOk,\r\n            onCancel,\r\n            onReset,\r\n            children,\r\n            ...others\r\n        } = this.props;\r\n        const { height } = this.state;\r\n        const prefixCls = this.context.getPrefixCls();\r\n        return (\r\n            <Spin spinning={loading} tip={loadingTip}>\r\n                <div\r\n                    className=\"modal-content\"\r\n                    ref={node => this.wrapper = node}\r\n                    style={{ display: 'flex', flexDirection: 'column', height, ...style }}\r\n                    {...others}\r\n                >\r\n                    <div\r\n                        className=\"modal-content-inner\"\r\n                        style={{ flex: 1, padding: 16, overflow: surplusSpace ? 'auto' : '', ...bodyStyle }}\r\n                    >\r\n                        {children}\r\n                    </div>\r\n                    {footer !== false ? (\r\n                        <div className={`${prefixCls}-modal-footer`} style={{ flex: 0 }}>\r\n                            {footer ? footer : (\r\n                                <>\r\n                                    <Button type=\"primary\" onClick={onOk} htmlType={okHtmlType}>{okText}</Button>\r\n                                    {onReset ? <Button onClick={onReset}>{resetText}</Button> : null}\r\n                                    <Button onClick={onCancel}>{cancelText}</Button>\r\n                                </>\r\n                            )}\r\n                        </div>\r\n                    ) : null}\r\n                </div>\r\n            </Spin>\r\n        );\r\n    }\r\n}\r\n"},"util/index.js":{"import":"../../util","content":"import { cloneDeep } from 'lodash';\r\nimport { pathToRegexp } from 'path-to-regexp';\r\nimport * as tree from './tree';\r\n\r\nconst ROUTE_BASE_NAME = process.env.BASE_NAME || '';\r\n\r\nconst { getNodeByPropertyAndValue, convertToTree } = tree;\r\n\r\nexport const isMobile = document.body.clientWidth < 575;\r\n\r\n/**\r\n * 根据path获取对应的菜单\r\n * @param path\r\n * @param menuTreeData\r\n * @returns {*}\r\n */\r\nexport function getSelectedMenuByPath(path, menuTreeData) {\r\n    path = path.replace(ROUTE_BASE_NAME, '');\r\n    let selectedMenu;\r\n    if (menuTreeData) {\r\n        if (path.indexOf('/_') > -1) {\r\n            path = path.substring(0, path.indexOf('/_'));\r\n        }\r\n\r\n        // 先精确匹配\r\n        selectedMenu = getNodeByPropertyAndValue(menuTreeData, 'path', path, (itemValue, value, item) => {\r\n            const isTop = item.children && item.children.length;\r\n            return itemValue === value && !isTop; // 排除父级节点\r\n        });\r\n\r\n        // 正则匹配，路由中有`:id`的情况\r\n        // fixme 容易出问题：a/b/:id,会匹配 a/b/1, a/b/detail，有可能不是期望的结果，注意路由写法，a/b/tab/:id 具体的:id，添加一级，用来表明id是什么\r\n        if (!selectedMenu && path !== '/') {\r\n            selectedMenu = getNodeByPropertyAndValue(menuTreeData, 'path', path, (itemValue, value, item) => {\r\n                const isTop = item.children && item.children.length;\r\n                const re = pathToRegexp(itemValue);\r\n                return !!re.exec(value) && !isTop; // 排除父级节点\r\n            });\r\n        }\r\n    }\r\n    return selectedMenu;\r\n}\r\n\r\n/**\r\n * 获取菜单树状结构数据 和 随菜单携带过来的权限\r\n * @param menus 扁平化菜单数据\r\n */\r\nexport function getMenuTreeDataAndPermissions(menus) {\r\n    // 用户权限code，通过菜单携带过来的 1 => 菜单 2 => 功能\r\n    const permissions = menus.map(item => {\r\n        if (item.type === '1') return item.key;\r\n        if (item.type === '2') return item.code;\r\n        return null;\r\n    });\r\n\r\n    // 获取菜单，过滤掉功能码\r\n    menus = menus.filter(item => item.type !== '2');\r\n\r\n    // 设置basePath\r\n    const setBasePath = (node, basePath) => {\r\n        if (!basePath) return;\r\n\r\n        const { path, url } = node;\r\n\r\n        if (basePath.endsWith('/')) {\r\n            basePath = basePath.substr(0, basePath.length - 1);\r\n        }\r\n\r\n        if (path && !path.startsWith(basePath)) {\r\n            node.path = `${basePath}${path}`;\r\n        }\r\n\r\n        if (\r\n            url\r\n            && !url.startsWith('http')\r\n            && !url.startsWith('//')\r\n            && !url.startsWith(basePath)\r\n        ) {\r\n            node.url = `${basePath}${url}`;\r\n        }\r\n    };\r\n\r\n    const loop = (nodes, basePath) => {\r\n        nodes.forEach(item => {\r\n            const { key } = item;\r\n            const children = menus.filter(it => it.parentKey === key);\r\n\r\n            setBasePath(item, basePath);\r\n\r\n            if (children?.length) {\r\n                loop(children, basePath);\r\n            }\r\n        });\r\n    };\r\n\r\n    menus.forEach(top => {\r\n        const { basePath, key } = top;\r\n        const children = menus.filter(it => it.parentKey === key);\r\n\r\n        if (!basePath) return;\r\n\r\n        setBasePath(top, basePath);\r\n\r\n        if (children?.length) {\r\n            loop(children, basePath);\r\n        }\r\n    });\r\n\r\n    // 处理path： 只声明了url，为iframe页面\r\n    menus = menus.map(item => {\r\n        if (item.url) {\r\n            item.path = `/iframe_page_/${window.encodeURIComponent(item.url)}`;\r\n        }\r\n        return item;\r\n    });\r\n\r\n    // 菜单根据order 排序\r\n    const orderedData = [ ...menus ].sort((a, b) => {\r\n        const aOrder = a.order || 0;\r\n        const bOrder = b.order || 0;\r\n\r\n        // 如果order都不存在，根据 text 排序\r\n        if (!aOrder && !bOrder) {\r\n            return a.text > b.text ? 1 : -1;\r\n        }\r\n\r\n        return bOrder - aOrder;\r\n    });\r\n\r\n    // 设置顶级节点path，有的顶级没有指定path，默认设置为子孙节点的第一个path\r\n    const findPath = (node) => {\r\n        const children = orderedData.filter(item => item.parentKey === node.key);\r\n        let path = '';\r\n        if (children && children.length) {\r\n            for (let i = 0; i < children.length; i++) {\r\n                const child = children[i];\r\n                if (child.path) {\r\n                    path = child.path;\r\n                    break;\r\n                }\r\n                path = findPath(child);\r\n            }\r\n        }\r\n        return path;\r\n    };\r\n\r\n    orderedData.forEach(item => {\r\n        if (!item.path) {\r\n            item.path = findPath(item);\r\n        }\r\n    });\r\n\r\n    const menuTreeData = convertToTree(orderedData);\r\n    return { menuTreeData, permissions };\r\n}\r\n\r\n\r\n/**\r\n * 复合函数工具\r\n * @param functions\r\n * @returns {*}\r\n */\r\nexport function compose(functions) {\r\n    if (functions.length === 0) {\r\n        return arg => arg;\r\n    }\r\n\r\n    if (functions.length === 1) {\r\n        return functions[0];\r\n    }\r\n\r\n    return functions.reduce((a, b) => (...args) => a(b(...args)));\r\n}\r\n\r\n/**\r\n * 加载 JavaScript\r\n * @param src\r\n * @returns {Promise<any>}\r\n */\r\nexport function loadScript(src) {\r\n    return new Promise((resolve, reject) => {\r\n        const script = document.createElement('script');\r\n        script.type = 'text/javascript';\r\n        script.src = src;\r\n        script.onload = resolve;\r\n        script.onerror = reject;\r\n        document.head.appendChild(script);\r\n    });\r\n}\r\n\r\n/**\r\n * 判断字符串是否符合json各式\r\n * @param str\r\n * @returns {boolean}\r\n */\r\nexport function isJson(str) {\r\n    try {\r\n        if (typeof JSON.parse(str) == 'object') {\r\n            return true;\r\n        }\r\n    } catch (e) {\r\n        return false;\r\n    }\r\n}\r\n\r\n/**\r\n * 通用的一些工具方法\r\n * @module 通用工具方法\r\n * */\r\n\r\n/**\r\n * 字符串中所有单词首字母大写\r\n * @param {String} str\r\n * @returns {String}\r\n */\r\nexport function firstUpperCase(str) {\r\n    const s = typeof str !== 'string' ? `${str}` : str;\r\n    return s.replace(/\\b(\\w)(\\w*)/g, ($0, $1, $2) => $1.toUpperCase() + $2);\r\n}\r\n\r\n\r\n/**\r\n * 字符串中所有单词首字母小写\r\n * @param {String} str\r\n * @returns {String}\r\n */\r\nexport function firstLowerCase(str) {\r\n    const s = typeof str !== 'string' ? `${str}` : str;\r\n    return s.replace(/\\b(\\w)(\\w*)/g, ($0, $1, $2) => $1.toLowerCase() + $2);\r\n}\r\n\r\n/**\r\n * 获取字符串字节长度，中文占两个字节\r\n * @param {String} value\r\n * @returns {number}\r\n */\r\nexport function getStringByteLength(value) {\r\n    if (!value) return 0;\r\n    const s = typeof value !== 'string' ? `${value}` : value;\r\n    let length = s.length;\r\n\r\n    for (let i = 0; i < s.length; i++) {\r\n        if (s.charCodeAt(i) > 127) {\r\n            length++;\r\n        }\r\n    }\r\n\r\n    return length;\r\n}\r\n\r\n/**\r\n * 格式化字符串\r\n * @example\r\n * stringFormat('H{0}llo W{1}rld!', 'e', 'o');\r\n * stringFormat('H{eKey}llo W{oKey}rld!', {eKey: 'e', oKey: 'o'});\r\n * @param {String} value 需要格式化的字符串\r\n * @param {*} args 对象或者多个参数\r\n * @returns {*}\r\n */\r\nexport function stringFormat(value, ...args) {\r\n    if (!value) return value;\r\n    if (typeof value !== 'string') return value;\r\n    if (!args || !args.length) return value;\r\n\r\n    if (args.length === 1 && typeof (args[0]) === 'object') {\r\n        const arg = args[0];\r\n        Object.keys(arg).forEach(key => {\r\n            if (arg[key] !== undefined) {\r\n                const reg = new RegExp(`({${key}})`, 'g');\r\n                value = value.replace(reg, arg[key]);\r\n            }\r\n        });\r\n        return value;\r\n    }\r\n\r\n    for (let i = 0; i < args.length; i++) {\r\n        if (args[i] !== undefined) {\r\n            let reg = new RegExp(`({)${i}(})`, 'g');\r\n            value = value.replace(reg, args[i]);\r\n        }\r\n    }\r\n    return value;\r\n}\r\n\r\n/**\r\n * 获取cookie\r\n * @param {String} objName 存储coolie中数据的key\r\n * @returns {String}\r\n */\r\nexport function getCookie(objName) {\r\n    let arrStr = document.cookie.split('; ');\r\n    for (let i = 0; i < arrStr.length; i++) {\r\n        let temp = arrStr[i].split('=');\r\n        if (temp[0] === objName) return unescape(temp[1]);\r\n    }\r\n    return '';\r\n}\r\n\r\n/**\r\n * 获取浏览器\r\n * @returns {number}\r\n */\r\nexport function getScrollBarWidth() {\r\n    let scrollDiv = document.createElement('div');\r\n    scrollDiv.style.position = 'absolute';\r\n    scrollDiv.style.top = '-9999px';\r\n    scrollDiv.style.width = '50px';\r\n    scrollDiv.style.height = '50px';\r\n    scrollDiv.style.overflow = 'scroll';\r\n    document.body.appendChild(scrollDiv);\r\n    let scrollBarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;\r\n    window.document.body.removeChild(scrollDiv);\r\n    return scrollBarWidth;\r\n}\r\n\r\n/**\r\n * 判断是否有滚动条\r\n * @param el\r\n * @param direction\r\n * @returns {boolean}\r\n */\r\nexport function hasScrollBar(el, direction = 'vertical') {\r\n    if (direction === 'vertical') {\r\n        return el.scrollHeight > el.clientHeight;\r\n    } else if (direction === 'horizontal') {\r\n        return el.scrollWidth > el.clientWidth;\r\n    }\r\n}\r\n\r\n/**\r\n * 获得一个指定范围内的随机数\r\n * @param {number} min 最范围\r\n * @param {number} max 最大范围\r\n * @returns {number}\r\n */\r\nexport function getRandomNum(min, max) {\r\n    const range = max - min;\r\n    const rand = Math.random();\r\n    return (min + Math.round(rand * range));\r\n}\r\n\r\n/**\r\n * 获取一个元素距离浏览器顶部高度\r\n * @param element\r\n * @returns {number | Requireable<number>}\r\n */\r\nexport function getElementTop(element) {\r\n    if (!element) return 0;\r\n    let actualTop = element.offsetTop;\r\n    let current = element.offsetParent;\r\n\r\n    while (current !== null) {\r\n        actualTop += current.offsetTop;\r\n        current = current.offsetParent;\r\n    }\r\n\r\n    return actualTop;\r\n}\r\n\r\n/**\r\n * 根据className 获取父级元素\r\n * @param el\r\n * @param parentClassName\r\n * @returns {*}\r\n */\r\nexport function getParentByClassName(el, parentClassName) {\r\n    const parentNode = el.parentNode;\r\n    if (!parentNode) return null;\r\n\r\n    const classList = Array.from(parentNode.classList || []);\r\n\r\n    if (classList?.length && classList.includes(parentClassName)) {\r\n        return parentNode;\r\n    } else {\r\n        return getParentByClassName(parentNode, parentClassName);\r\n    }\r\n}\r\n\r\n/**\r\n * 为一个dom元素移除class\r\n * @param {string} selector document.querySelectory 要到的选择器\r\n * @param {string} className 要移除的class\r\n */\r\nexport function removeClass(selector, className) {\r\n    let doms = selector;\r\n    if (typeof selector === 'string') {\r\n        doms = document.querySelectorAll(selector);\r\n    }\r\n    if (!doms || !doms.length) return;\r\n    if (!doms.length) doms = [ doms ];\r\n    doms.forEach(dom => {\r\n        let domClass = dom.className;\r\n        if (domClass) {\r\n            domClass = domClass.split(' ');\r\n            if (!domClass || !domClass.length) return;\r\n            dom.className = domClass.filter(c => c !== className).join(' ');\r\n        }\r\n    });\r\n}\r\n\r\n/**\r\n * 为一个dom元素添加class\r\n * @param {string} selector document.querySelectory 要到的选择器\r\n * @param {string} className 要添加的class\r\n */\r\nexport function addClass(selector, className) {\r\n    let doms = selector;\r\n    if (typeof selector === 'string') {\r\n        doms = document.querySelectorAll(selector);\r\n    }\r\n    if (!doms || !doms.length) return;\r\n    if (!doms.length) doms = [ doms ];\r\n    doms.forEach(dom => {\r\n        let domClass = dom.className;\r\n        if (domClass) {\r\n            domClass = domClass.split(' ');\r\n            if (!domClass || !domClass.length || domClass.indexOf(className) > -1) return;\r\n            domClass.push(className);\r\n            dom.className = domClass.join(' ');\r\n        } else {\r\n            dom.className = className;\r\n        }\r\n    });\r\n}\r\n\r\n/**\r\n * 拼接get请求所需url\r\n * @param {string} url\r\n * @param {object} params 请求参数\r\n * @returns {string} 拼接后的url\r\n */\r\nexport function mosaicUrl(url, params) {\r\n    if (!params) return url;\r\n    const queryString = [];\r\n    Object.keys(params).forEach(key => {\r\n        let value = params[key];\r\n        if (value !== undefined && value !== null) {\r\n            queryString.push(`${key}=${value}`);\r\n        }\r\n    });\r\n    const qStr = queryString.join('&');\r\n    if (url.indexOf('?') < 0) {\r\n        url += `?${qStr}`;\r\n    } else if (url.endsWith('&')) {\r\n        url += qStr;\r\n    } else if (url.endsWith('?')) {\r\n        url += `${qStr}`;\r\n    } else {\r\n        url += `&${qStr}`;\r\n    }\r\n    return url;\r\n}\r\n\r\n/**\r\n * 根据keyPath查找一个object中的数据\r\n * @param obj 需要查找的对象\r\n * @param {string} keyPath 类似： a.b.c\r\n * @returns {*} 查找到的数据\r\n */\r\nfunction findObjByKeyPath(obj, keyPath) {\r\n    const keys = keyPath.split('.');\r\n    let targetObj = obj;\r\n    keys.forEach(k => {\r\n        targetObj = targetObj[k];\r\n    });\r\n    return targetObj;\r\n}\r\n\r\n/**\r\n * 从数组中删除一个元素\r\n * @param {Array} arr 需要操作的数组\r\n * @param {*} item 要删除的元素，注意：内部是用'==='比对的\r\n */\r\nexport function arrayRemove(arr, item) {\r\n    if (!arr || !Array.isArray(arr) || !arr.length) return arr;\r\n    const newArr = cloneDeep(arr);\r\n    let itemIndex = -1;\r\n    for (let i = 0; i < newArr.length; i++) {\r\n        if (newArr[i] === item) {\r\n            itemIndex = i;\r\n            break;\r\n        }\r\n    }\r\n    if (itemIndex > -1) {\r\n        newArr.splice(itemIndex, 1);\r\n    }\r\n    return newArr;\r\n}\r\n\r\n/**\r\n * 从数组中删除一些元素\r\n * @param {Array} arr 需要操作的数组\r\n * @param {Array} items 需要删除的元素\r\n */\r\nexport function arrayRemoveAll(arr, items) {\r\n    if (!arr || !Array.isArray(arr) || !arr.length) return arr;\r\n    if (!items || !Array.isArray(items) || !items.length) return arr;\r\n    return arr.filter(item => {\r\n        return !items.find(it => it === item);\r\n    });\r\n}\r\n\r\n/**\r\n * 加入元素到数组中，如果已存在就不添加了\r\n * @param array\r\n * @param item\r\n * @returns {...*[]}\r\n */\r\nexport function arrayPush(array, item) {\r\n    if (!array || !Array.isArray(array)) return array;\r\n\r\n    const arr = [ ...array ];\r\n    if (!arr.includes(item)) arr.push(item);\r\n\r\n    return arr;\r\n}\r\n\r\n/**\r\n * 根据指定keyPath 添加元素\r\n * @param obj 要操作的数据\r\n * @param {string} keyPath 类似于：a.b.c，就会把value赋值给c\r\n * @param {*} value 要设置的数据\r\n * @throws Will throw error if keyPath dose not point to an object\r\n */\r\nexport function objSetValue(obj, keyPath, value) {\r\n    const newObj = cloneDeep(obj);\r\n    const pointLastIndex = keyPath.lastIndexOf('.');\r\n    if (pointLastIndex < 0) {\r\n        if (typeof newObj !== 'object') {\r\n            throw new Error('keyPath dose not point to an object!');\r\n        }\r\n        newObj[keyPath] = value;\r\n        return newObj;\r\n    }\r\n    const key = keyPath.substr(pointLastIndex + 1, keyPath.length);\r\n    keyPath = keyPath.substr(0, pointLastIndex);\r\n    let targetObj = findObjByKeyPath(newObj, keyPath);\r\n    if (typeof targetObj !== 'object') {\r\n        throw new Error('keyPath dose not point to an object!');\r\n    }\r\n    targetObj[key] = value;\r\n    return newObj;\r\n}\r\n\r\n/**\r\n * 根据keyPath定位到指定元素，并将其删除\r\n * @param obj 要操作的数据\r\n * @param {string} keyPath keyPath 类似于：a.b.c，会把c删除\r\n * @throws Will throw error if keyPath dose not point to an object\r\n */\r\nexport function objRemove(obj, keyPath) {\r\n    const newObj = cloneDeep(obj);\r\n    const pointLastIndex = keyPath.lastIndexOf('.');\r\n    if (pointLastIndex < 0) {\r\n        if (typeof newObj !== 'object') {\r\n            throw new Error('keyPath dose not point to an object!');\r\n        }\r\n        delete newObj[keyPath];\r\n        return newObj;\r\n    }\r\n    const key = keyPath.substr(pointLastIndex + 1, keyPath.length);\r\n    keyPath = keyPath.substr(0, pointLastIndex);\r\n    let targetObj = findObjByKeyPath(newObj, keyPath);\r\n    if (typeof targetObj !== 'object') {\r\n        throw new Error('keyPath dose not point to an object!');\r\n    }\r\n    delete targetObj[key];\r\n    return newObj;\r\n}\r\n\r\n/**\r\n * 根据keyPath定位到指定数组，并添加元素\r\n * @param obj 要操作的数据\r\n * @param keyPath 类似于：a.b.c，通过keyPath，定位到obj中某个数组\r\n * @param value 需要append的元素\r\n * @throws Will throw error if keyPath dose not point to an array\r\n */\r\nexport function arrAppendValue(obj, keyPath, value) {\r\n    const newObj = cloneDeep(obj);\r\n    let targetObj = findObjByKeyPath(newObj, keyPath);\r\n    if (!Array.isArray(targetObj)) {\r\n        throw new Error('keyPath dose not point to an array!');\r\n    }\r\n    if (Array.isArray(value) && value.length) {\r\n        value.forEach(v => targetObj.push(v));\r\n    } else {\r\n        targetObj.push(value);\r\n    }\r\n    return newObj;\r\n}\r\n\r\n/**\r\n * 根据keyPath定位到指定数组，删除一个元素\r\n * @param obj 要操作的数据\r\n * @param keyPath 类似于：a.b.c，通过keyPath，定位到obj中某个数组\r\n * @param value 需要删除的数组元素\r\n * @throws Will throw error if keyPath dose not point to an array\r\n */\r\nexport function arrRemove(obj, keyPath, value) {\r\n    const newObj = cloneDeep(obj);\r\n    let targetObj = findObjByKeyPath(newObj, keyPath);\r\n    if (!Array.isArray(targetObj)) {\r\n        throw new Error('keyPath dose not point to an array!');\r\n    }\r\n    targetObj = arrayRemove(targetObj, value);\r\n    return objSetValue(newObj, keyPath, targetObj);\r\n}\r\n\r\n/**\r\n * 根据keyPath定位到指定数组，删除所有跟value相同的元素\r\n * @param obj 要操作的数据\r\n * @param keyPath 类似于：a.b.c，通过keyPath，定位到obj中某个数组\r\n * @param value 移除的数组元素\r\n * @throws Will throw error if keyPath dose not point to an array\r\n */\r\nexport function arrRemoveAll(obj, keyPath, value) {\r\n    const newObj = cloneDeep(obj);\r\n    let targetObj = findObjByKeyPath(newObj, keyPath);\r\n    if (!Array.isArray(targetObj)) {\r\n        throw new Error('keyPath dose not point to an array!');\r\n    }\r\n    while (targetObj.indexOf(value) > -1) {\r\n        targetObj = arrayRemove(targetObj, value);\r\n    }\r\n    return objSetValue(newObj, keyPath, targetObj);\r\n}\r\n\r\n/**\r\n * 数组去重，此方法不改变原有数据，返回新的数组\r\n * @param {Array} array\r\n * @returns {Array} 新数组\r\n */\r\nexport function uniqueArray(array) {\r\n    const n = {}; // hash 表\r\n    const r = []; // 临时数组\r\n    for (let i = 0; i < array.length; i++) { // 遍历当前数组\r\n        if (!n[array[i]]) { // 如果hash表中没有当前项\r\n            n[array[i]] = true; // 存入hash表\r\n            r.push(array[i]); // 把当前数组的当前项push到临时数组里面\r\n        }\r\n    }\r\n    return r;\r\n}\r\n\r\n/**\r\n * 获取浏览器窗口大小\r\n * @returns {{width: (Number|number), height: (Number|number)}}\r\n */\r\nexport function getWindowSize() {\r\n    const w = window;\r\n    const d = document;\r\n    const e = d.documentElement;\r\n    const g = d.getElementsByTagName('body')[0];\r\n    const width = w.innerWidth || e.clientWidth || g.clientWidth;\r\n    const height = w.innerHeight || e.clientHeight || g.clientHeight;\r\n    return { width, height };\r\n}\r\n\r\n/**\r\n * 为dom元素添加事件\r\n * @param element {Object} 需要添加事件的dom元素\r\n * @param type {String} 事件名称，比如 'click'\r\n * @param handler {function} 事件处理函数\r\n */\r\nexport function addEventListener(element, type, handler) {\r\n    if (!element) return;\r\n    if (element.addEventListener) {\r\n        element.addEventListener(type, handler, false);\r\n    } else if (element.attachEvent) {\r\n        element.attachEvent(`on${type}`, handler);\r\n    } else {\r\n        element[`on${type}`] = handler;\r\n    }\r\n}\r\n\r\n/**\r\n * 为dom元素移除事件\r\n * @param element {Object} 需要添加事件的dom元素\r\n * @param type {String} 事件名称，比如 'click'\r\n * @param handler {function} 事件处理函数\r\n */\r\nexport function removeEventListener(element, type, handler) {\r\n    if (!element) return;\r\n    if (element.removeEventListener) {\r\n        element.removeEventListener(type, handler, false);\r\n    } else if (element.detachEvent) {\r\n        element.detachEvent(`on${type}`, handler);\r\n    } else {\r\n        element[`on${type}`] = null;\r\n    }\r\n}\r\n\r\n/**\r\n * 将数值四舍五入后格式化成金额形式\r\n *\r\n * @param num 数值(Number或者String)\r\n * @param options 可选参数\r\n * @param options.prefix 金钱前缀，默认为空，一般为 ￥ 或 $\r\n * @param options.decimalNum 保留小数点个数，默认为2 一般为 0 1 2\r\n * @param options.splitSymbol 格式化分割符，默认为英文逗号，分隔符必须是单字符\r\n * @return 金额格式的字符串,如'￥1,234,567.45'\r\n * @type String\r\n */\r\nexport function formatCurrency(num, options = {}) {\r\n    let { decimalNum, splitSymbol } = options;\r\n    const { prefix = '￥' } = options;\r\n    let centsPercent = 100;\r\n    if (splitSymbol === undefined) splitSymbol = ',';\r\n    if (decimalNum !== 0 && decimalNum !== 1 && decimalNum !== 2) decimalNum = 2;\r\n    if (decimalNum === 0) centsPercent = 1;\r\n    if (decimalNum === 1) centsPercent = 10;\r\n    num = num.toString().replace(/\\$|,/g, '');\r\n    if (isNaN(num)) num = '0';\r\n    const sign = (num === Math.abs(num).toString()) ? '' : '-';\r\n    num = Math.abs(num);\r\n    num = Math.floor((num * centsPercent) + 0.50000000001);\r\n    let cents = num % centsPercent;\r\n    num = Math.floor(num / centsPercent).toString();\r\n    if (cents < 10 && decimalNum === 2) {\r\n        cents = `0${cents}`;\r\n    }\r\n    for (let i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++) {\r\n        const endPosition = (4 * i) + 3;\r\n        num = num.substring(0, num.length - endPosition)\r\n            + splitSymbol + num.substring(num.length - endPosition);\r\n    }\r\n    if (decimalNum === 0) {\r\n        return prefix + sign + num;\r\n    }\r\n    return `${prefix}${sign}${num}.${cents}`;\r\n}\r\n"},"tree.js":{"import":"./tree","content":"/**\r\n * 树操作通用方法，将一些常用方法提炼出来，方便使用。\r\n * @module 树操作工具\r\n */\r\n\r\nimport { cloneDeep } from 'lodash';\r\n\r\n/**\r\n * 从数组中删除一些元素\r\n * @param {Array} arr 需要操作的数组\r\n * @param {Array} items 需要删除的元素\r\n */\r\nexport function arrayRemoveAll(arr, items) {\r\n    if (!arr || !Array.isArray(arr) || !arr.length) return arr;\r\n    if (!items || !Array.isArray(items) || !items.length) return arr;\r\n    return arr.filter(item => {\r\n        return !items.find(it => it === item);\r\n    });\r\n}\r\n\r\n/**\r\n * 数组去重，此方法不改变原有数据，返回新的数组\r\n * @param {Array} array\r\n * @returns {Array} 新数组\r\n */\r\nexport function uniqueArray(array) {\r\n    const n = {}; // hash 表\r\n    const r = []; // 临时数组\r\n    for (let i = 0; i < array.length; i++) { // 遍历当前数组\r\n        if (!n[array[i]]) { // 如果hash表中没有当前项\r\n            n[array[i]] = true; // 存入hash表\r\n            r.push(array[i]); // 把当前数组的当前项push到临时数组里面\r\n        }\r\n    }\r\n    return r;\r\n}\r\n\r\n/**\r\n * 从数组中删除一个元素\r\n * @param {Array} arr 需要操作的数组\r\n * @param {*} item 要删除的元素，注意：内部是用'==='比对的\r\n */\r\nexport function arrayRemove(arr, item) {\r\n    if (!arr || !Array.isArray(arr) || !arr.length) return arr;\r\n    const newArr = cloneDeep(arr);\r\n    let itemIndex = -1;\r\n    for (let i = 0; i < newArr.length; i++) {\r\n        if (newArr[i] === item) {\r\n            itemIndex = i;\r\n            break;\r\n        }\r\n    }\r\n    if (itemIndex > -1) {\r\n        newArr.splice(itemIndex, 1);\r\n    }\r\n    return newArr;\r\n}\r\n\r\n/**\r\n * 将数据转换成tree所需格式\r\n * @param {object} data 要进行转换的object\r\n * @param {String} [keyField='id'] 指定data中某个字段转换为树所需的key\r\n * @param {String} [titleField='name'] 指定data中某个字段转换为树所需的name\r\n * @returns {{name: *, key: *}}\r\n */\r\nexport function generateTreeNode(data, keyField = 'id', titleField = 'name') {\r\n    return { ...data, title: data[titleField], key: data[keyField] };\r\n}\r\n\r\n/**\r\n * 将数据转换成tree所需格式\r\n * @param {Array} data 要进行转换的一些数据\r\n * @param {String} [keyField='id'] 指定data中某个字段转换为树所需的key\r\n * @param {String} [titleField='name'] 指定data中某个字段转换为树所需的name\r\n * @returns {Array}\r\n */\r\nexport function generateTreeNodes(data, keyField = 'id', titleField = 'name') {\r\n    let arr = [];\r\n    if (data && data.length) {\r\n        arr = data.map(d => generateTreeNode(d, keyField, titleField));\r\n    }\r\n    return arr;\r\n}\r\n\r\n/**\r\n * 根据key 将node设置成叶子节点\r\n * @param {Array} treeData 树的树状结构数据\r\n * @param {String} key 节点的key值\r\n */\r\nexport function setLeaf(treeData, key) {\r\n    const loopLeaf = (data) => {\r\n        for (let item of data) {\r\n            if (item.key === key) {\r\n                item.isLeaf = true;\r\n                break;\r\n            }\r\n            if (item.children && item.children.length) {\r\n                loopLeaf(item.children);\r\n            }\r\n        }\r\n    };\r\n    loopLeaf(treeData);\r\n}\r\n\r\n/**\r\n * 给指定key的节点添加子节点\r\n * @param {Array} treeData 树的树状结构数据\r\n * @param {String} key 节点的key值\r\n * @param {Array} child 要添加的子节点\r\n */\r\nexport function appendChildrenByKey(treeData, key, child) {\r\n    const loop = (data) => {\r\n        for (let item of data) {\r\n            if (key === item.key) {\r\n                if (item.children) {\r\n                    item.children = item.children.concat(child);\r\n                } else {\r\n                    item.children = child;\r\n                }\r\n\r\n                if (!item.children || !item.children.length) {\r\n                    setLeaf(treeData, key);\r\n                }\r\n                break;\r\n            }\r\n            if (item.children && item.children.length) {\r\n                loop(item.children);\r\n            }\r\n        }\r\n    };\r\n    loop(treeData);\r\n}\r\n\r\n/**\r\n * 检测某个节点是否有parent节点\r\n * @param {Array} rows 所有节点，扁平数据，非树状结构\r\n * @param {object} row 需要判断得节点\r\n * @returns {boolean}\r\n */\r\nexport function hasParent(rows, row) {\r\n    let parentKey = row.parentKey;\r\n    return rows.find(r => r.key === parentKey);\r\n}\r\n\r\n/**\r\n * 根据key，查询其所有后代节点，一般会用于删除\r\n * @param {Array} rows 具有key，parentKey关系的扁平数据结构\r\n * @param {object} key 要查询的节点 key\r\n * @returns {Array}\r\n */\r\nexport function getGenerationsByKey(rows, key) {\r\n    // 这个函数会被多次调用，对rows做深拷贝，否则会产生副作用。\r\n    rows = cloneDeep(rows);\r\n    const parentNode = rows.find(item => item.key === key);\r\n    if (!parentNode) return [];\r\n\r\n\r\n    let nodes = [ parentNode ];\r\n    let generationNodes = [ cloneDeep(parentNode) ];\r\n\r\n    // 存放要处理的节点\r\n    let toDo = nodes.map((v) => v);\r\n\r\n    while (toDo.length) {\r\n        // 处理一个，头部弹出一个。\r\n        let node = toDo.shift();\r\n        // 获取子节点。\r\n        rows.forEach(row => {\r\n            if (row.parentKey === node.key) {\r\n                let child = cloneDeep(row);\r\n                generationNodes.push(child);\r\n                // child加入toDo，继续处理\r\n                toDo.push(child);\r\n            }\r\n        });\r\n    }\r\n    return generationNodes;\r\n}\r\n\r\n\r\n/**\r\n * js构造树方法。会给节点添加parentKeys,parentNodes,parentTexts属性，方便后期数据提取\r\n * @param {Array} rows 具有key，parentKey关系的扁平数据结构，标题字段为text\r\n * @param {object} [parentNode=null] 开始节点\r\n * @returns {Array}\r\n */\r\nexport function convertToTree(rows, parentNode = null) {\r\n    // 这个函数会被多次调用，对rows做深拷贝，否则会产生副作用。\r\n    rows = cloneDeep(rows);\r\n    parentNode = cloneDeep(parentNode);\r\n\r\n    let nodes = [];\r\n    if (parentNode) {\r\n        nodes.push(parentNode);\r\n    } else { // 获取所有的顶级节点\r\n        nodes = rows.filter(r => !hasParent(rows, r));\r\n    }\r\n\r\n    // 存放要处理的节点\r\n    let toDo = nodes.map((v) => v);\r\n\r\n    while (toDo.length) {\r\n        // 处理一个，头部弹出一个。\r\n        let node = toDo.shift();\r\n        // 获取子节点。\r\n        rows.forEach(row => {\r\n            if (row.parentKey === node.key) {\r\n                let child = cloneDeep(row);\r\n                let parentKeys = [ node.key ];\r\n                if (node.parentKeys) {\r\n                    parentKeys = node.parentKeys.concat(node.key);\r\n                }\r\n                child.parentKeys = parentKeys;\r\n\r\n                let parentTexts = [ node.text ];\r\n                if (node.parentTexts) {\r\n                    parentTexts = node.parentTexts.concat(node.text);\r\n                }\r\n                child.parentTexts = parentTexts;\r\n\r\n                const tempNode = cloneDeep(node);\r\n                delete tempNode.children;\r\n                delete tempNode.parentKeys;\r\n                delete tempNode.parentNodes;\r\n                delete tempNode.parentTexts;\r\n                let parentNodes = [ tempNode ];\r\n                if (node.parentNodes) {\r\n                    parentNodes = node.parentNodes.concat(parentNodes);\r\n                }\r\n                child.parentNodes = parentNodes;\r\n\r\n                if (node.children) {\r\n                    node.children.push(child);\r\n                } else {\r\n                    node.children = [ child ];\r\n                }\r\n                // child加入toDo，继续处理\r\n                toDo.push(child);\r\n            }\r\n        });\r\n    }\r\n\r\n    if (parentNode) {\r\n        return nodes[0].children;\r\n    }\r\n    return nodes;\r\n}\r\n\r\n/**\r\n * 根据指定数据的键值对，查找node，比如根据path查找： getNodeByPropertyAndValue(treeData, 'path', '/user/list')\r\n * @param {Array} treeData 树状结构数据\r\n * @param {String} key key值，比如'path'，'text'等节点数据属性\r\n * @param {*} value 节点属性所对应的数据\r\n * @param {Function} [compare] 节点属性所对应的数据比较方式， 默认 === 比对\r\n * @returns {object} 返回根据 key value查找到的节点\r\n */\r\nexport function getNodeByPropertyAndValue(treeData, key, value, compare) {\r\n    if (!treeData || !treeData.length) return null;\r\n    if (!compare) compare = (a, b, item) => a === b;\r\n    let node = null;\r\n    const loop = (data) => {\r\n        for (let item of data) {\r\n            if (compare(item[key], value, item)) {\r\n                node = { ...item };\r\n                break;\r\n            }\r\n            if (item.children && item.children.length) {\r\n                loop(item.children);\r\n            }\r\n        }\r\n    };\r\n    loop(treeData);\r\n    return node;\r\n}\r\n\r\n/**\r\n * 根据key查找节点\r\n * @param {Array} treeData 树状结构数据\r\n * @param {String} key\r\n * @returns {object} 根据key查找到的节点\r\n */\r\nexport function getNodeByKey(treeData, key) {\r\n    return getNodeByPropertyAndValue(treeData, 'key', key);\r\n}\r\n\r\n/**\r\n * 根据key查找后代元素的key\r\n * @param {Array} treeData 树状结构数据\r\n * @param {String} key\r\n * @returns {*[]} 根据key查找到的所有后代节点key\r\n */\r\nexport function getGenerationKeys(treeData, key) {\r\n    const node = getNodeByKey(treeData, key);\r\n    const keys = [];\r\n    const loop = (node) => {\r\n        const { key, children } = node;\r\n        keys.push(key);\r\n\r\n        if (children?.length) {\r\n            children.forEach(loop);\r\n        }\r\n    };\r\n    loop(node);\r\n\r\n    return keys.filter(item => item !== key);\r\n}\r\n\r\n/**\r\n * 根据key查找所有后代元素\r\n * @param {Array} treeData 树状结构数据\r\n * @param {String} key\r\n * @returns {Array} 根据key查找到的所有后代节点\r\n */\r\nexport function getGenerationalNodesByKey(treeData, key) {\r\n    const node = getNodeByKey(treeData, key);\r\n    if (!node.children || !node.children.length) {\r\n        return [];\r\n    }\r\n    const allNodes = [];\r\n    const loop = (data) => {\r\n        data.forEach(d => {\r\n            allNodes.push(d);\r\n            if (d.children && d.children) {\r\n                loop(d.children);\r\n            }\r\n        });\r\n    };\r\n    loop(node.children);\r\n    return allNodes;\r\n}\r\n\r\n/**\r\n * 获取选中节点的keys，点击父节点时，其下所有后代元素将被全被选中，或者全不选中，选中子节点时，其所有祖先节点将被选中\r\n * @param treeData 树状结构数据\r\n * @param {Array} checkedKeys 点击过之后，树选中的keys\r\n * @param {boolean} checked 当前点击时 checked （true）还是 unchecked（false）\r\n * @param {String} checkNodeKey 当前点击节点的key\r\n * @returns {Array} 选中的keys\r\n */\r\nexport function getCheckedKeys(treeData, checkedKeys, checked, checkNodeKey) {\r\n    // TODO 区分半选和全选\r\n    let allKeys = [ ...checkedKeys ];\r\n    const generationalNodes = getGenerationalNodesByKey(treeData, checkNodeKey);\r\n    const generationalKeys = generationalNodes.map(n => n.key);\r\n\r\n    if (checked) {\r\n        // 选中所有后代节点\r\n        allKeys = allKeys.concat(generationalKeys);\r\n\r\n        // 选中有祖先节点\r\n        const node = getNodeByKey(treeData, checkNodeKey);\r\n        if (node.parentKeys) {\r\n            allKeys = allKeys.concat(node.parentKeys);\r\n        }\r\n    } else {\r\n        // 取消选中所有后代节点\r\n        allKeys = arrayRemoveAll(allKeys, generationalKeys.concat(checkNodeKey));\r\n\r\n        // 判断其父节点是否还有子节点选中了，如果没有，父节点也不选中\r\n        const node = getNodeByKey(treeData, checkNodeKey);\r\n        if (node.parentKeys) {\r\n            const pks = [ ...node.parentKeys ];\r\n            pks.reverse();\r\n            pks.forEach(key => {\r\n                const pNode = getNodeByKey(treeData, key);\r\n                if (pNode.children && pNode.children.length) {\r\n                    let hasCheckedChild = false;\r\n                    for (let pCNode of pNode.children) {\r\n                        if (allKeys.indexOf(pCNode.key) > -1) {\r\n                            hasCheckedChild = true;\r\n                            break;\r\n                        }\r\n                    }\r\n                    if (!hasCheckedChild) {\r\n                        allKeys = arrayRemove(allKeys, key);\r\n                    }\r\n                }\r\n            });\r\n        }\r\n    }\r\n    return uniqueArray(allKeys);\r\n}\r\n\r\n/**\r\n * 根据key删除节点\r\n * @param {Array} treeData 树的树状结构数据\r\n * @param {String} key 要删除节点的key值\r\n */\r\nexport function removeNodeByKey(treeData, key) {\r\n    if (!treeData || !treeData.length) return null;\r\n    const loop = (data) => {\r\n        for (let i = 0; i < data.length; i++) {\r\n            const item = data[i];\r\n            if (item.key === key) {\r\n                data.splice(i, 1);\r\n                break;\r\n            } else if (item.children && item.children.length) {\r\n                loop(item.children);\r\n            }\r\n        }\r\n    };\r\n    loop(treeData);\r\n}\r\n\r\n/**\r\n * 给指定key的node节点增加一个新的子节点\r\n * @param {Array} treeData 树的树状结构数据\r\n * @param {String} key 要操作的节点的key值\r\n * @param {object} newNode 需要加入的子节点\r\n */\r\nexport function addNodeChildByKey(treeData, key, newNode) {\r\n    if (!treeData || !treeData.length) return null;\r\n    newNode.isLeaf = true;\r\n    const loop = (data) => {\r\n        for (let item of data) {\r\n            if (item.key === key) {\r\n                if (item.children) {\r\n                    item.children.push({ ...newNode });\r\n                } else {\r\n                    item.children = [ { ...newNode } ];\r\n                }\r\n                break;\r\n            }\r\n            if (item.children && item.children.length) {\r\n                loop(item.children);\r\n            }\r\n        }\r\n    };\r\n    loop(treeData);\r\n}\r\n\r\n/**\r\n * 更新某个节点\r\n * @param {Array} treeData 树的树状结构数据\r\n * @param {object} newNode 需要跟新的节点新数据，会根据key对原数据进行比对\r\n */\r\nexport function updateNode(treeData, newNode) {\r\n    if (!treeData || !treeData.length) return null;\r\n    const loop = (data) => {\r\n        for (let item of data) {\r\n            if (item.key === newNode.key) {\r\n                Object.keys(item).forEach(key => {\r\n                    item[key] = newNode[key];\r\n                });\r\n                break;\r\n            }\r\n            if (item.children && item.children.length) {\r\n                loop(item.children);\r\n            }\r\n        }\r\n    };\r\n    loop(treeData);\r\n}\r\n\r\n/**\r\n * 根据某个节点，获取其最顶级节点\r\n * @param {Array} treeData 树状结构数据\r\n * @param {object} node 节点数据\r\n * @returns {object} 最顶层节点\r\n */\r\nexport function getTopNodeByNode(treeData, node) {\r\n    if (!treeData || !treeData.length || !node) return null;\r\n\r\n    if (node && !node.parentKey) return node;\r\n    let parentNode = null;\r\n    const loop = (data) => { // 查找node的父节点\r\n        for (let item of data) {\r\n            if (item.key === node.parentKey) {\r\n                parentNode = { ...item };\r\n                break;\r\n            }\r\n            if (item.children && item.children.length) {\r\n                loop(item.children);\r\n            }\r\n        }\r\n    };\r\n    loop(treeData);\r\n    return getTopNodeByNode(treeData, parentNode); // 继续查找parentNode的父节点\r\n}\r\n\r\n/**\r\n * 渲染树，cb(node[, children nodes])\r\n * @param {Array} treeData 树的树状结构数据\r\n * @param {function} cb 回调函数：cb(node[, children nodes])\r\n */\r\nexport function renderNode(treeData, cb) {\r\n    const loop = data => data.map((item) => {\r\n        if (item.children) {\r\n            return cb(item, loop(item.children)); // item children Item\r\n        }\r\n\r\n        return cb(item); // 叶子节点\r\n    });\r\n    return loop(treeData);\r\n}\r\n\r\n/**\r\n * 查找给定节点，及其后代节点property属性，第一个不为空的值\r\n * @param {Array} treeData 树的树状结构数据\r\n * @param {object} node 节点数据\r\n * @param {String} property 属性，比如 key， path等\r\n * @returns {*}\r\n */\r\nexport function getFirstValue(treeData, node, property) {\r\n    if (node[property]) return node[property];\r\n    let firstValue = null;\r\n    const loop = data => {\r\n        for (let item of data) {\r\n            if (item[property]) {\r\n                firstValue = item[property];\r\n                break;\r\n            }\r\n            if (item.children && item.children.length) {\r\n                loop(item.children);\r\n            }\r\n        }\r\n    };\r\n    if (node.children && node.children.length) {\r\n        loop(node.children);\r\n    }\r\n    return firstValue;\r\n}\r\n"}},"dependencies":{"react":{"version":">=16.9.0"},"@ant-design/icons":{"version":"4.5.0"},"prop-types":{"version":"15.7.2"},"lodash.camelcase":{"version":"4.3.0"},"lodash.upperfirst":{"version":"4.3.1"},"rc-util":{"version":"5.8.1"},"react-dom":{"version":">=16.9.0"},"antd":{"version":"4.13.0","css":"antd/dist/antd.css"},"lodash":{"version":"4.17.21"},"path-to-regexp":{"version":"6.2.0"}},"identifier":"icon-demo-1"},
  },
};
